using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Practices.Composite.Modularity;

namespace PrismNavigationFramework.Infrastructure
{
    public class ModuleNamesRegistrationService : IModuleNamesRegistrationService
    {
        private readonly IModuleCatalog _moduleCatalog;
        private readonly Dictionary<string, string> _registeredModuleNames = new Dictionary<string, string>();

        public ModuleNamesRegistrationService(IModuleCatalog moduleCatalog)
        {
            _moduleCatalog = moduleCatalog;
            this.DefaultModuleNameFormat = "{0}Module.InitModule";
        }

        public void RegisterModuleName(string urlFriendlyModuleName, string realModuleName)
        {
            if (this._registeredModuleNames.ContainsKey(urlFriendlyModuleName))
            {
                if (realModuleName.ToLower() != this._registeredModuleNames[urlFriendlyModuleName].ToLower())
                throw new InvalidOperationException(string.Format("You cannot register UrlFriendlyModule name {0} twice with different real module names {1} and {2}.", urlFriendlyModuleName, realModuleName, this._registeredModuleNames[urlFriendlyModuleName]));
            }
            else
            {
                this._registeredModuleNames.Add(urlFriendlyModuleName, realModuleName);
            }
        }

        public string DefaultModuleNameFormat { get; set; }     

        private ModuleInfo GetModuleInfoFromModuleCatalog(string moduleName)
        {
            return this._moduleCatalog.Modules.Where(p => p.ModuleName.ToLower() == moduleName.ToLower()).
                    FirstOrDefault();
        }

        public string GetRealModuleName(string urlFriendlyModuleName)
        {
            // first if user registered this urlfriendlymodule name and if so use it to get full name of module
            var registeredModuleName = this._registeredModuleNames.Keys.Where(p => p.ToLower() == urlFriendlyModuleName.ToLower()).FirstOrDefault();
            if (registeredModuleName != null)
            {
                return this._registeredModuleNames[registeredModuleName];
            }

            // now lets see if we have module with this name registered in our ModuleCatalog
            var moduleInCatalog = this.GetModuleInfoFromModuleCatalog(urlFriendlyModuleName);              
            if (moduleInCatalog != null)
            {
                // lets register this name so its cached for future use
                this.RegisterModuleName(urlFriendlyModuleName, moduleInCatalog.ModuleName);
                return moduleInCatalog.ModuleName;
            }

            // if nothing else try to build module name using DefaultModuleNameFormat
            var moduleNameFromFormat = string.Format(DefaultModuleNameFormat, urlFriendlyModuleName);
            moduleInCatalog = this.GetModuleInfoFromModuleCatalog(moduleNameFromFormat);

            if (moduleInCatalog != null)
            {
                // lets register this name so its cached for future use
                this.RegisterModuleName(urlFriendlyModuleName, moduleInCatalog.ModuleName);
                return moduleInCatalog.ModuleName;
            }

            throw new Exception(string.Format("Could not find a way to identify module with name {0}",
                                              urlFriendlyModuleName));
        }
    }
}